#include "encoder.h"

// 正交编码器PCNT初始化
void encoder_init(pcnt_unit_t pcnt_unit,int pin0,int pin1) {
    pcnt_config_t pcnt_config = {
        .pulse_gpio_num = pin0,
        .ctrl_gpio_num = pin1,
        .lctrl_mode = PCNT_MODE_KEEP,
        .hctrl_mode = PCNT_MODE_REVERSE,
        .pos_mode = PCNT_COUNT_INC,//PCNT_COUNT_DIS,//如果使用PCNT_COUNT_DIS将关闭上升检查
        .neg_mode = PCNT_COUNT_DEC,
        .counter_h_lim = INT16_MAX,
        .counter_l_lim = INT16_MIN,
        .unit = pcnt_unit,
        .channel = PCNT_CHANNEL_0
    };
    pcnt_unit_config(&pcnt_config);
    pcnt_event_enable(pcnt_unit,PCNT_EVT_L_LIM);
    pcnt_event_enable(pcnt_unit,PCNT_EVT_H_LIM);
    pcnt_event_enable(pcnt_unit, PCNT_EVT_ZERO);
    pcnt_intr_enable(pcnt_unit);

    //pcnt_set_filter_value(unit,1023); //滤波器，如果线路存在杂波可以尝试打开
    //pcnt_filter_enable(unit);
    pcnt_counter_pause(pcnt_unit);
    pcnt_counter_clear(pcnt_unit);
    pcnt_counter_resume(pcnt_unit);
}

// 初始化扩展编码器
void encoder_ext_init(encoder_t *encoder, pcnt_unit_t unit) {
    encoder->unit = unit;
    encoder->total_count = 0;
    encoder->prev_count = 0;
    
    // 获取初始计数值
    pcnt_get_counter_value(unit, &encoder->prev_count);
}

// 读取扩展后的计数值（处理溢出）
int32_t encoder_get_count(encoder_t *encoder) {
    int16_t current_count = 0;
    uint32_t status = 0;
    
    // 读取当前计数值
    pcnt_get_counter_value(encoder->unit, &current_count);
    
    // 读取事件状态（自动清除事件标志）
    pcnt_get_event_status(encoder->unit, &status);
    
    // 计算增量值（考虑溢出）
    int32_t delta = (int32_t)current_count - (int32_t)encoder->prev_count;
    
    // 处理溢出情况
    if (status & PCNT_EVT_H_LIM) {
        // 正向溢出：从最大值回到最小值
        if (delta < 0) {
            delta += (INT16_MAX - INT16_MIN + 1);
        }
    }
    else if (status & PCNT_EVT_L_LIM) {
        // 负向溢出：从最小值回到最大值
        if (delta > 0) {
            delta -= (INT16_MAX - INT16_MIN + 1);
        }
    }else if (status & PCNT_EVT_ZERO) {
        // 执行归零特殊处理
        encoder->total_count = 0;
    }
    
    // 更新总计数
    encoder->total_count += delta;
    encoder->prev_count = current_count;
    
    return encoder->total_count;
}    